---
title: Middleware
description: Aprende cómo usar un middleware en Astro.
i18nReady: true
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';

Un **Middleware** te permite interceptar las solicitudes y respuestas e inyectar comportamientos dinámicamente cada vez que una página o endpoint está a punto de ser renderizado. Esta renderización se produce en tiempo de compilación para todas las páginas prerenderizadas, pero se produce cuando se solicita la ruta para las páginas renderizadas bajo demanda.  

El middleware también permite establecer y compartir información específica de la solicitud entre endpoints y páginas mutando un objeto `locals` que está disponible en todos los componentes Astro y endpoints API. Este objeto está disponible incluso cuando este middleware se ejecuta en tiempo de compilación.

## Uso básico

1. Crea `src/middleware.js|ts` (Alternativamente, puedes crear `src/middleware/index.js|ts`.)

2. Dentro de este archivo, exporta una función [`onRequest()`](/es/reference/api-reference/#onrequest) a la que se le pueda pasar un [objeto `context`](#el-objeto-context) y la función `next()`. Esta no debe ser una exportación por defecto.

    ```js title="src/middleware.js"
    export function onRequest ({ locals, request }, next) {
        // interceptar los datos de una solicitud.
        // opcionalmente, modifica las propiedades en `locals`.
        locals.title = "Nuevo título";

        // devuelve una respuesta o el resultado de llamar a `next()`.
        return next();
    };
    ```

3. Dentro de cualquier archivo `.astro`, puedes acceder a los datos de respuesta utilizando `Astro.locals`. 

    ```astro title="src/components/Component.astro"
    ---
    const data = Astro.locals;
    ---
    <h1>{data.title}</h1>
    <p>Este {data.property} proviene de un middleware.</p>

    ```

### El objeto `context`

El objeto [`context`](/es/reference/api-reference/#contexto-del-endpoint) incluye información que estará disponible para otros middlewares, rutas de la API y rutas `.astro` durante el proceso de renderizado.

Esto es un argumento opcional pasado a `onRequest()` que puede contener el objeto `locals` así como cualquier propiedad adicional que se comparta durante el renderizado. Por ejemplo, el objeto `context` puede incluir cookies utilizadas en la autenticación.

### Almacenando datos en `context.locals`

`context.locals` es un objeto que se puede manipular dentro del middleware.

Este objeto `locals` se reenvía a lo largo del proceso de manejo de la solicitud y está disponible como una propiedad de [`APIContext`](/es/reference/api-reference/#contexto-del-endpoint) y [`AstroGlobal`](/es/reference/api-reference/#astrolocals). Esto permite compartir datos entre middlewares, rutas de la API y páginas `.astro`. Esto es útil para almacenar datos específicos de la solicitud, como datos de usuario, durante el paso de renderizado.

:::tip[Propiedades de la integración]
Las [Integraciones](/es/guides/integrations-guide/) pueden establecer propiedades y proporcionar funcionalidad a través del objeto `locals`. Si estás utilizando una integración, comprueba su documentación para asegurarte de que no estás sobrescribiendo ninguna de sus propiedades o realizando trabajo innecesario.
:::

Puedes almacenar cualquier tipo de datos dentro de `locals`: cadenas de texto, números e incluso tipos de datos complejos como funciones y maps.


```js title="src/middleware.js"
export function onRequest ({ locals, request }, next) {
    // interceptar los datos de una solicitud.
    // opcionalmente, modifica las propiedades en `locals`.
    locals.user.name = "John Wick";
    locals.welcomeTitle = () => {
        return "Bienvenido de nuevo  " + locals.user.name;
    };

  // devuelve una respuesta o el resultado de llamar a `next()`.
  return next();
};
```
Luego puedes utilizar esta información dentro de cualquier archivo `.astro` con `Astro.locals`.

```astro title="src/pages/orders.astro"
---
const title = Astro.locals.welcomeTitle();
const orders = Array.from(Astro.locals.orders.entries());
---
<h1>{title}</h1>
<p>Este {data.property} proviene de un middleware.</p>
<ul>
    {orders.map(order => {
        return <li>{/* haz algo con cada orden */}</li>
    })}
</ul>
```

`locals` es un objeto que existe y se destruye dentro de una sola ruta de Astro; cuando se renderiza la página de la ruta, `locals` dejará de existir y se creará uno nuevo. La información que necesita persistir a través de múltiples solicitudes de página debe almacenarse en otro lugar.

:::note
El valor de `locals` no se puede sobrescribir en tiempo de ejecución. Hacerlo podría eliminar toda la información almacenada por el usuario. En el modo `dev`, Astro realiza comprobaciones y lanzará un error si se intenta sobrescribir `locals`.
:::

### Ejemplo: Redactando información sensible

El ejemplo a continuación utiliza un middleware para reemplazar "PRIVATE INFO" con la palabra "REDACTED" y así permitirte mostrar HTML modificado en tu página:

```js title="src/middleware.js"
export const onRequest = async (context, next) => {
    const response = await next();
    const html = await response.text();
    const redactedHtml = html.replaceAll("PRIVATE INFO", "REDACTED");
    
    return new Response(redactedHtml, {
        status: 200,
        headers: response.headers
    });
};
```

## Tipos de middleware

Puedes importar y usar la función de utilidad `defineMiddleware()` para aprovechar la seguridad de tipos:

```ts
// src/middleware.ts
import { defineMiddleware } from "astro:middleware";

// `context` y `next` son automáticamente tipados
export const onRequest = defineMiddleware((context, next) => {

});
```

En cambio, si estás utilizando JsDoc para aprovechar la seguridad de tipos, puedes utilizar `MiddlewareHandler`:

```js
// src/middleware.js
/**
 * @type {import("astro").MiddlewareHandler}
 */
// `context` y `next` son automáticamente tipados
export const onRequest = (context, next) => {

};
```

Para tipar la información dentro de `Astro.locals`, lo que te da autocompletado dentro de los archivos `.astro` y el código del middleware, declara un namespace global en el archivo `env.d.ts`:

```ts title="src/env.d.ts"
/// <reference types="astro/client" />
declare namespace App {
    interface Locals {
        user: {
            name: string
        },
        welcomeTitle: () => string,
        orders: Map<string, object>
    }
}
```

Luego, dentro del archivo de middleware, puedes aprovechar el autocompletado y la seguridad de tipos.

## Encadenando el middleware

Múltiples middlewares pueden ser unidos en un orden específico utilizando [`sequence()`](/es/reference/api-reference/#sequence):

```js title="src/middleware.js"
import { sequence } from "astro:middleware";

async function validation(_, next) {
    console.log("solicitud de validación");
    const response = await next();
    console.log("respuesta de validación");
    return response;
}

async function auth(_, next) {
  console.log("solicitud de autenticación");
  const response = await next();
  console.log("respuesta de autenticación");
  return response;

}

async function greeting(_, next) {
  console.log("solicitud de saludo");
  const response = await next();
  console.log("respuesta de saludo");
  return response;

}

export const onRequest = sequence(validation, auth, greeting);
```

Esto resultará en el siguiente orden en la consola:

```sh
solicitud de validación
solicitud de autenticación
solicitud de saludo
respuesta de saludo
respuesta de autenticación
respuesta de validación
```

## Páginas de error

El middleware intentará ejecutarse para todas las páginas renderizadas bajo demanda, incluso cuando no se pueda encontrar una ruta coincidente. Esto incluye la página 404 por defecto (en blanco) de Astro y cualquier página 404 personalizada. Sin embargo, depende del [adaptador](/es/guides/server-side-rendering/) decidir si ese código se ejecuta. Algunos adaptadores pueden servir una página de error específica de la plataforma en su lugar.

El middleware también intentará ejecutarse antes de servir una página de error 500, incluyendo una página 500 personalizada, a menos que el error del servidor se haya producido en la ejecución del propio middleware. Si tu middleware no se ejecuta correctamente, entonces no tendrás acceso a `Astro.locals` para renderizar tu página 500.